import Canvas = WechatMiniprogram.Canvas

export class Animator {
  static currentTimeMillsecond = () => {
    if (typeof performance === 'undefined') return new Date().getTime()
    
    return performance.now()
  }
  
  canvas?: Canvas
  startValue = 0
  endValue = 0
  duration = 0
  loops = 1
  fillRule = 0
  running = false
  startTime = 0
  currentFrication = 0.0
  reverseBool = false
  
  onStart = () => {}
  onUpdate = (value: number) => {}
  onEnd = () => {}
  
  start(currentValue?: number) {
    this.startFunc(false, currentValue)
  }
  
  reverse(currentValue?: number) {
    this.startFunc(true, currentValue)
  }
  
  stop() {
    this.stopFunc()
  }
  
  getAnimateValue(): number {
    return (this.endValue - this.startValue) * this.currentFrication + this.startValue
  }
  
  private startFunc(reverse: boolean, currentValue: number | undefined = undefined) {
    this.reverseBool = reverse
    this.running = true
    this.startTime = Animator.currentTimeMillsecond()
    if (currentValue) {
      if (reverse) {
        this.startTime -= (1.0 - currentValue / (this.endValue - this.startValue)) * this.duration
      } else {
        this.startTime -= (currentValue / (this.endValue - this.startValue)) * this.duration
      }
    }
    
    this.currentFrication = 0.0
    this.onStart()
    this.frameFunc()
  }
  
  private frameFunc() {
    const renderLoop = () => {
      if (!this.running) return
      
      this.deltaTimeFunc(Animator.currentTimeMillsecond() - this.startTime)
      
      this.canvas.requestAnimationFrame(renderLoop)
    }
    
    this.canvas.requestAnimationFrame(renderLoop)
  }
  
  private deltaTimeFunc(deltaTime: number) {
    let ended = false
    if (deltaTime >= this.duration * this.loops) {
      this.currentFrication = this.fillRule === 1 ? 0.0 : 1.0
      this.running = false
      ended = true
    } else {
      this.currentFrication = (deltaTime % this.duration) / this.duration
      if (this.reverseBool) this.currentFrication = 1.0 - this.currentFrication
    }
    
    this.onUpdate(this.getAnimateValue())
    if (!this.running && ended) this.onEnd()
  }
  
  private stopFunc() {
    this.running = false
  }
}